package com.zhxin.nettylab.decoder.chapter2;

import com.zhxin.nettylab.decoder.chapter1.StringProcessHandler;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.string.StringDecoder;
import org.junit.Assert;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketOption;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Set;

/**
 * @ClassName NettyLengthBasedDecoderDemo
 * @Description //LengthFieldBasedFrameDecoder 解码器使用Demo
 * @Author singleZhang
 * @Email 405780096@qq.com
 * @Date 2020/12/7 0007 下午 4:13
 **/
public class NettyLengthBasedDecoderDemo {
    private String s = "SingleZhang 学习Netty 笔记记录！";
    private final static int VERSION = 100;

    /**
     * LengthFieldBasedFrameDecoder DEMO1
     * */
    @Test
    public void testLineBasedFrameDecoder(){

        try{
            /*
             * 第1个参数maxFrameLength设置为1024，表示数据包的最大长度为1024。
             * 第2个参数lengthFieldOffset设置为0，表示长度字段的偏移量为0，也就是长度字段放在了最前面，处于数据包的起始位置。
             * 第3个参数lengthFieldLength设置为4，表示长度字段的长度为4个字节，即表示内容长度的值占用数据包的4个字节。
             * 第4个参数lengthAdjustment设置为0，长度调整值的计算公式为：内容字段偏移量-长度字段偏移量-长度字段的字节数，
             * 在上面示例程序中实际的值为：4-0-4 =0。
             * 第5个参数initialBytesToStrip为4，表示获取最终内容Content的字节数组时，抛弃最前面的4个字节的数据。
             */
            final LengthFieldBasedFrameDecoder spliter = new LengthFieldBasedFrameDecoder(1024,
                    0,4,0,4);
            /*
             * 第1个参数maxFrameLength可以为1024，表示数据包的最大长度为1024个字节。
             * 第2个参数lengthFieldOffset为0，表示长度字段处于数据包的起始位置。
             * 第3个参数lengthFieldLength实例中的值为4，表示长度字段的长度为4个字节。
             * 第4个参数lengthAdjustment为2，
             * 长度调整值的计算方法为：内容字段偏移量 -长度字段偏移量 - 长度字段的长度 = 6-0-4 = 2；
             * 即 lengthAdjustment就是夹在内容字段和长度字段中的部分——版本号的长度。
             * 第5个参数initialBytesToStrip为6，表示获取最终Content内容的字节数组时，抛弃最前面的6个字节数据。
             * 即，长度字段、版本字段的值被抛弃。
             */
            //final LengthFieldBasedFrameDecoder spliter = new LengthFieldBasedFrameDecoder(1024,0,4,2,6);
            /*
             * 第1个参数maxFrameLength可以设置为1024，表示数据包的最大长度为1024个字节。
             * 第2个参数lengthFieldOffset可以设置为2，表示长度字段处于版本号的后面。
             * 第3个参数lengthFieldLength可以设置为4，表示长度字段为4个字节。
             * 第4个参数lengthAdjustment可以设置为4，
             * 长度调整的计算方法为：内容字段偏移量 - 长度字段偏移量 - 长度字段的长度 = 10-2-4 = 4。
             * lengthAdjustment就是夹在内容字段和长度字段中的部分——版本字段的长度。
             * 第5个参数initialBytesToStrip可以设置为10，表示获取最终Content内容的字节数组时，抛弃最前面的10个字节数据。换句话说，长度字段、版本字段、魔数字段的值被抛弃。
             */
            //final LengthFieldBasedFrameDecoder spliter = new LengthFieldBasedFrameDecoder(1024,2,4,4,10);
            ChannelInitializer initializer = new ChannelInitializer<EmbeddedChannel>() {
                @Override
                protected void initChannel(EmbeddedChannel ch) throws Exception {

                    /*
                     * 添加流水线
                     * 先添加解码器
                     * 再添加业务流程处理器
                     * */
                    ch.pipeline().addLast(spliter);
                    ch.pipeline().addLast(new StringDecoder(StandardCharsets.UTF_8));
                    ch.pipeline().addLast(new StringProcessHandler());
                }
            };
            EmbeddedChannel channel = new EmbeddedChannel(initializer);
            for(int i =1;i<=100;i++){

                ByteBuf buffer = Unpooled.buffer();
                String sendStr = i+"次发送:"+s;
                byte[] bytes = sendStr.getBytes(StandardCharsets.UTF_8);
                buffer.writeInt(bytes.length);
                buffer.writeBytes(bytes);

                channel.writeInbound(buffer); // 往Channel 写入 Buffer数据
            }

            Thread.sleep(Integer.MAX_VALUE);

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
